﻿using DevExpress.Blazor.Primitives.Internal;
using DevExpress.CodeParser;
using DeviceDetectorNET;
using Newtonsoft.Json.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using System.Xml;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using YamlDotNet.Core.Tokens;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Exams;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.ExtendCells;
using XmlNode = System.Xml.XmlNode;

namespace YAPACS.RisServer.Services
{
    /// <summary>
    /// 报告扩展信息
    /// </summary>
    public class ReportExtendsService(IRepository<Report, Guid> reportRep,
                                      ICellFactoryService cellFactory,
                                      IRepository<ExamDataElement, Guid> dataElementRep) : DomainService, IReportExtendsService, ITransientDependency
    {
        private readonly IRepository<Report, Guid> _reportRepository = reportRep;
        private readonly ICellFactoryService _cellFactory = cellFactory;
        private readonly IRepository<ExamDataElement, Guid> _dataElementRep = dataElementRep;


        #region 解析报告样式，生成扩展信息AmisSchema
        /// <summary>
        ///解析报告样式，生成扩展信息的AmisSchema
        /// </summary>
        /// <param name="reportOid"></param>
        /// <returns></returns>
        public async Task<JObject> GetSchemaAndDataAsync(Guid reportOid)
        {
            JObject schema = new JObject();
            try
            {
                Report report = await _reportRepository.GetAsync(reportOid);
                ReportStyle reportStyle = report.ReportStyle;
                string xmlString = Encoding.UTF8.GetString(reportStyle.Content); // 转为字符串
                xmlString = System.Text.RegularExpressions.Regex.Replace(xmlString, "^[^<]", ""); // 去除web序列化引起的隐藏字符
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlString);
                XmlNode root = xmlDoc.DocumentElement;
                XmlNode controls = root.SelectSingleNode("Controls"); // 定位拓展表格        
                List<XmlNode> rows = null;
                // 获取controls下名称为"table_"开头的Item
                foreach (XmlNode item in controls.ChildNodes)
                {
                    if (item.Attributes["Name"].Value.ToString().Contains("extendsTable"))
                    {
                        rows.Concat(item.SelectSingleNode("Rows").ChildNodes.ToDynamicList<XmlNode>());
                    }
                }
                if (rows != null)
                {
                    schema.Add("type", "flex");
                    schema.Add("direction", "column");// 轴沿竖直方向
                    JObject flexStyle = new JObject();
                    flexStyle.Add("justifyContent", "flex-start");
                    schema.Add("style", flexStyle);// 左对齐

                    JArray items = new JArray();
                    int rowIndex = 0;
                    foreach (XmlNode node in rows)  // rows的子节点
                    {
                        rowIndex++;
                        string nodeName = node.Name;
                        if (nodeName.Contains("Item")) // 子节点名字含有"Item"
                        {
                            // 行flex
                            JObject flex = new JObject();
                            flex.Add("type", "flex");
                            flex.Add("direction", "row");
                            // 行flex样式
                            JObject rowFlexStyle = new JObject();
                            rowFlexStyle.Add("position", "relative");
                            rowFlexStyle.Add("inset", "auto");
                            rowFlexStyle.Add("flexWrap", "nowrap");
                            rowFlexStyle.Add("justifyContent", "flex-start");
                            flex.Add("style", rowFlexStyle);

                            JArray rowFlexItems = new JArray();// 行flex中的单元格
                            XmlNodeList cells = node.SelectSingleNode("Cells").ChildNodes; // 单元格集合
                            foreach (XmlNode cell in cells)
                            {
                                JObject container = new JObject();
                                container.Add("type", "container");
                                container.Add("isFixedHeight", true);
                                JObject style = new JObject();

                                double originalWidth = Convert.ToDouble(cell.Attributes["Weight"].Value);
                                // 计算百分比宽度
                                string width = WidthCoculate(Convert.ToDouble(cell.Attributes["Weight"].Value)).ToString();
                                style.Add("width", width + "%");
                                JObject body = new JObject();
                                string text = null;

                                //计算单元格实际高度
                                string height = "35px";
                                bool hasRowSpan = cell.Attributes["RowSpan"] != null;
                                if (hasRowSpan)
                                {
                                    // 占位
                                    JObject placeHolderContainer = new JObject();
                                    placeHolderContainer.Add("type", "container");
                                    placeHolderContainer.Add("isFixedHeight", true);
                                    JObject placeHolderStyle = new JObject();
                                    placeHolderStyle.Add("height", "35px");
                                    placeHolderStyle.Add("flexBasis", width + "%");
                                    placeHolderContainer.Add("style", placeHolderStyle);
                                    rowFlexItems.Add(placeHolderContainer);

                                    int rowSpan = Convert.ToInt32(cell.Attributes["RowSpan"].Value);
                                    height = (rowSpan * 35).ToString() + "px";
                                    container.Add("className", "row-span");  // 跨行样式
                                    style.Add("position", "absolute");
                                }
                                else
                                {
                                    style.Add("position", "static");
                                }
                                style.Add("height", height);
                                style.Add("overflowX", "overflowX");
                                style.Add("overflowY", "visible");

                                if (originalWidth > 0)//有宽度，无宽度内部不渲染任何组件
                                {
                                    if (cell.Attributes["Text"] != null)
                                    {
                                        text = cell.Attributes["Text"].Value;
                                    }
                                    if (text != null) // 单元格只展示文字
                                    {
                                        body.Add("type", "tpl");
                                        body.Add("tpl", text);
                                        body.Add("inline", false);
                                        if (rowIndex != 1)// 普通行，普通label
                                        {
                                            style.Add("display", "flex");
                                            style.Add("flex", "0 0 " + width);
                                            style.Add("flexWrap", "nowrap");
                                            style.Add("justifyContent", "flex-end");
                                            style.Add("flexDirection", "row");
                                            style.Add("alignItems", "center");
                                            if (!hasRowSpan)// 普通label
                                            {
                                                body.Add("className", "extend-label");
                                            }
                                            else // 跨行label
                                            {
                                                body.Add("className", "row-Span-Label");
                                            }
                                        }
                                        else
                                        {
                                            body.Add("className", "title-Row-Container-body");
                                        }
                                    }
                                    else  // 显示控件
                                    {

                                        style.Add("display", "block");
                                        style.Add("flex", "0 0 " + width);

                                        // 判断控件类型
                                        body.Add("type", "input-text");
                                        body.Add("name", "report.reportExtending." + cell.Attributes["Name"].Value);
                                        body.Add("mode", "normal");
                                    }
                                }
                                container.Add("body", body);
                                container.Add("style", style);
                                rowFlexItems.Add(container);
                            }
                            flex.Add("items", rowFlexItems);
                            items.Add(flex);
                        }
                    }
                    schema.Add("items", items);
                }
            }
            catch (Exception e)
            {
                throw;
            }


            string test = schema.ToString();
            return schema;
        }
        #endregion


        #region 宽度计算 (百分比)
        /// <summary>
        /// 计算单元格宽度占比(1-12,)
        /// </summary>
        /// <param name="width"></param>
        /// <returns></returns>
        public float WidthCoculate(double width)
        {
            const double totalWeight = 3.8065711559172386;
            return (float)Math.Round((width / totalWeight) * 100, 2);
        }
        #endregion



        /// <summary>
        /// 生成schema
        /// </summary>
        /// <param name="reportOid"></param>
        /// <returns></returns>
        public async Task<JObject> GetSchemaAsync(Guid reportOid)
        {
            JObject schema = null;
            try
            {
                Report report = await _reportRepository.GetAsync(reportOid);
                if (report.ReportStyle != null)
                {
                    string xmlString = Encoding.UTF8.GetString(report.ReportStyle.Content); // 转为字符串
                    xmlString = System.Text.RegularExpressions.Regex.Replace(xmlString, "^[^<]", ""); // 去除web序列化引起的隐藏字符
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(xmlString);
                    XmlNodeList extendTables = xmlDoc.SelectNodes("//*[starts-with(@Name,'table_')]"); // 定位拓展表格  
                    List<XmlNode> extendFields = xmlDoc.SelectNodes("//*[starts-with(@Name,'field_')]").ToDynamicList<XmlNode>();

                    if (extendFields.Count == 0 && extendTables.Count == 0)
                    {
                        return null;
                    }
                    var fileds = extendFields.Where((e) => e.SelectSingleNode("ExpressionBindings").SelectSingleNode("Item1").Attributes["Expression"].Value.ToString().Contains("Json(")).ToList();
                    fileds = fileds.OrderByDescending(e => Convert.ToSingle(e.Attributes["LocationFloat"].Value.ToString().Split(',')[1]))
                                                .ThenBy(e => Convert.ToSingle(e.Attributes["LocationFloat"].Value.ToString().Split(',')[0])).ToList();
                    List<XmlNode> rows = new List<XmlNode>();
                    foreach (XmlNode item in extendTables)
                    {
                        var aa = item.SelectSingleNode("Rows").ChildNodes.ToDynamicArray<XmlNode>();
                        rows.AddRange(item.SelectSingleNode("Rows").ChildNodes.ToDynamicList<XmlNode>());
                    }
                    // 最外层flex
                    schema = new JObject
                    {
                        { "type", "flex" }
                    };
                    JObject flexStyle = new JObject
                    {
                        { "justifyContent", "flex-start" },
                        { "flexDirection", "column" }// 轴沿竖直方向
                    };
                    schema.Add("style", flexStyle);// 左对齐
                    JArray items = new JArray();

                    // 包含扩展字段
                    if (fileds != null && fileds.Count > 0)
                    {
                        RowFlex fieldRow = _cellFactory.NewRowFlex();
                        fieldRow.Style = new JObject
                        {
                            //{ "position", "relative" },
                            //{ "inset", "auto" },
                            { "flexWrap", "wrap" },
                            { "justifyContent", "flex-start" },
                            { "flexDirection","row"}
                        };
                        // 字段schema
                        for (int i = 0; i < fileds.Count; i++)
                        {
                            XmlNode field = fileds[i];
                            string text = field.Attributes["Name"].Value.ToString().Substring(6);

                            string tag;// 字段说明
                            if (field.Attributes["Tag"] != null)
                            {
                                tag = field.Attributes["Tag"].Value;
                            }
                            else
                            {
                                tag = "";
                            }
                            int tabIndex = 0;// tabIndex
                            if (field.Attributes["Bookmark"] != null)
                            {
                                int.TryParse(field.Attributes["Bookmark"].Value, out tabIndex);
                            }
                            XmlNode expressionNode = field.SelectSingleNode("ExpressionBindings").SelectSingleNode("Item1"); // 获取表达式节点
                            string key = GetKeyFromExpression(expressionNode.Attributes["Expression"].Value);  // 获取表达式key
                            var dataElement = await _dataElementRep.FindAsync(e => e.Name == key && e.IsActive && !e.IsDirectory); // 获取元数据

                            ApplicableSex applicableSex = new ApplicableSex();
                            switch (report.Exam.Patient.Sex)
                            {
                                case PatientSex.Male:
                                    applicableSex = ApplicableSex.Male;
                                    break;
                                case PatientSex.Female:
                                    applicableSex = ApplicableSex.Female;
                                    break;
                                case PatientSex.Other:
                                    applicableSex = ApplicableSex.None;
                                    break;

                                default:
                                    applicableSex = ApplicableSex.None;
                                    break;
                            }
                            if (dataElement != null && !dataElement.ApplicableSex.Equals(ApplicableSex.None) && !dataElement.ApplicableSex.Equals(applicableSex))
                            {
                                continue;
                            }
                            FieldControlCell controlCell = _cellFactory.NewFieldControlCell(key, dataElement, FieldControlCell.AutoWidth, tag, tabIndex);
                            fieldRow.Items.Add(controlCell.GetSchema());
                        }
                        items.Add(fieldRow.GetSchema());
                    }

                    // 包含扩展表格
                    if (rows != null && rows.Count > 0)
                    {
                        int rowIndex = 0;

                        // 表格schema
                        foreach (XmlNode node in rows)  // rows的子节点
                        {
                            rowIndex++;
                            string nodeName = node.Name;
                            if (nodeName.Contains("Item")) // 子节点名字含有"Item"
                            {
                                // 行flex
                                RowFlex rowFlex = _cellFactory.NewRowFlex();
                                XmlNodeList cells = node.SelectSingleNode("Cells").ChildNodes; // 单元格集合

                                foreach (XmlNode cell in cells)
                                {
                                    double originalWidth = Convert.ToDouble(cell.Attributes["Weight"].Value);
                                    string text = null;
                                    bool hasRowSpan = cell.Attributes["RowSpan"] != null;


                                    if (originalWidth > 0)//有宽度，无宽度内部不渲染任何组件
                                    {

                                        // 有表达式渲染组件
                                        if (cell.SelectNodes(".//*[starts-with(@Expression,'Json(')]").Count > 0)
                                        {
                                            XmlNode expressionNode = cell.SelectSingleNode("ExpressionBindings").SelectSingleNode("Item1");
                                            if (expressionNode != null)
                                            {
                                                string key = GetKeyFromExpression(expressionNode.Attributes["Expression"].Value);
                                                if (!string.IsNullOrEmpty(key))
                                                {
                                                    ExamDataElement dataElement = null;

                                                    string tag;
                                                    if (cell.Attributes["Tag"] != null)
                                                    {
                                                        tag = cell.Attributes["Tag"].Value;
                                                    }
                                                    else
                                                    {
                                                        tag = "";
                                                    }

                                                    int tabIndex = 0;
                                                    if (cell.Attributes["Bookmark"] != null)
                                                    {
                                                        int.TryParse(cell.Attributes["Bookmark"].Value, out tabIndex);
                                                    }

                                                    if (!string.IsNullOrEmpty(key))
                                                    {
                                                        dataElement = await _dataElementRep.FindAsync(e => e.Name == key && e.IsActive && !e.IsDirectory);
                                                    }
                                                    ControlCell controlCell = _cellFactory.NewControlCell(dataElement, key, originalWidth, tag, tabIndex);
                                                    JObject aa = controlCell.GetSchema();
                                                    rowFlex.Items.Add(controlCell.GetSchema());
                                                }
                                                else // key值无法解析
                                                {
                                                    PlaceholderCell placeholder = _cellFactory.NewPlaceholderCell(originalWidth);
                                                    rowFlex.Items.Add(placeholder.GetSchema());
                                                }
                                            }
                                            else  // 无表达式内层节点
                                            {
                                                PlaceholderCell placeholder = _cellFactory.NewPlaceholderCell(originalWidth);
                                                rowFlex.Items.Add(placeholder.GetSchema());
                                            }
                                        }
                                        else // 无表达式
                                        {
                                            // 文本单元格
                                            if (cell.Attributes["Text"] != null)
                                            {
                                                text = cell.Attributes["Text"].Value;
                                                string textAlign = GetTextAlignString(cell);
                                                if (hasRowSpan && Convert.ToInt32(cell.Attributes["RowSpan"].Value) > 1)// 跨行单元格
                                                {
                                                    int rowSpan = Convert.ToInt32(cell.Attributes["RowSpan"].Value);
                                                    MultiRowCell multiRowCell = _cellFactory.NewMultiRowCell(text, originalWidth, rowSpan, textAlign);
                                                    rowFlex.Items.Add(multiRowCell.GetSchema());
                                                    rowFlex.Items.Add(multiRowCell.PlaceHolderContainer);
                                                }
                                                else if (!hasRowSpan || Convert.ToInt32(cell.Attributes["RowSpan"].Value) <= 1) // 单行文本单元格
                                                {
                                                    TextCell textCell = _cellFactory.NewTextCell(text, originalWidth, textAlign);
                                                    rowFlex.Items.Add(textCell.GetSchema());
                                                }
                                            }
                                            else
                                            {
                                                PlaceholderCell placeholder = _cellFactory.NewPlaceholderCell(originalWidth);
                                                rowFlex.Items.Add(placeholder.GetSchema());
                                            }
                                        }
                                    }
                                }
                                items.Add(rowFlex.GetSchema());
                            }
                        }

                    }

                    if (items.Count > 0)
                    {
                        schema.Add("items", items);
                    }
                    else
                    {
                        schema = null;
                    }
                }
                else
                {
                    schema = null;
                }
            }
            catch (Exception e)
            {
                throw;
            }

            return schema;
        }

        /// <summary>
        /// 获取拓展字段
        /// </summary>
        /// <param name="reportOid"></param>
        /// <returns></returns>
        public async Task<JArray> GetExtendFieldsAsync(Guid reportOid)
        {
            JArray fields = [];
            Report report = await _reportRepository.GetAsync(reportOid);
            if (report.ReportStyle != null)
            {
                string xmlString = Encoding.UTF8.GetString(report.ReportStyle.Content); // 转为字符串
                xmlString = System.Text.RegularExpressions.Regex.Replace(xmlString, "^[^<]", ""); // 去除web序列化引起的隐藏字符
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlString);
                List<XmlNode> extendFields = xmlDoc.SelectNodes("//*[starts-with(@Name,'field_')]").ToDynamicList<XmlNode>();
                if (extendFields.Count == 0)
                {
                    return null;
                }
                var fileds = extendFields.Where((e) => e.SelectSingleNode("ExpressionBindings").SelectSingleNode("Item1").Attributes["Expression"].Value.ToString().Contains("Json(")).ToList();
                fileds = fileds.OrderByDescending(e => Convert.ToSingle(e.Attributes["LocationFloat"].Value.ToString().Split(',')[1]))
                                            .ThenBy(e => Convert.ToSingle(e.Attributes["LocationFloat"].Value.ToString().Split(',')[0])).ToList();
                // 包含扩展字段
                if (fileds != null && fileds.Count > 0)
                {
                    // 字段schema
                    for (int i = 0; i < fileds.Count; i++)
                    {
                        JObject obj = new JObject();
                        XmlNode field = fileds[i];
                        string label = field.Attributes["Name"].Value.ToString().Substring(6);
                        string tag;// 字段说明
                        if (field.Attributes["Tag"] != null)
                        {
                            tag = field.Attributes["Tag"].Value;
                        }
                        else
                        {
                            tag = "";
                        }
                        int tabIndex = 0;// tabIndex
                        if (field.Attributes["Bookmark"] != null)
                        {
                            int.TryParse(field.Attributes["Bookmark"].Value, out tabIndex);
                        }
                        XmlNode expressionNode = field.SelectSingleNode("ExpressionBindings").SelectSingleNode("Item1"); // 获取表达式节点
                        string name = GetKeyFromExpression(expressionNode.Attributes["Expression"].Value);  // 获取表达式key
                        var dataElement = await _dataElementRep.FindAsync(e => e.Name == name && e.IsActive && !e.IsDirectory); // 获取元数据

                        int applicableSex;
                        switch (report.Exam.Patient.Sex)
                        {
                            case PatientSex.Male:
                                applicableSex = 1;
                                break;
                            case PatientSex.Female:
                                applicableSex = 2;
                                break;
                            case PatientSex.Other:
                                applicableSex = 0;
                                break;

                            default:
                                applicableSex = 0;
                                break;
                        }
                        if (dataElement != null && !dataElement.ApplicableSex.Equals(ApplicableSex.None) && !dataElement.ApplicableSex.Equals(applicableSex))
                        {
                            continue;
                        }
                        obj.Add("label",label);
                        obj.Add("tag", tag);
                        if (dataElement != null)
                        {
                            if (string.IsNullOrEmpty(dataElement.Description))
                            {
                                obj["tag"] = dataElement.Description;
                            }
                            obj.Add("type", dataElement.ValueType.ToString()) ;
                            obj.Add("valueRange",dataElement.ValueRange);
                            obj.Add("isMultiLine", dataElement.IsMultiLine);
                            obj.Add("isMultiValue", dataElement.IsMultiValue) ;
                            JArray referenceValues =new();
                            if (dataElement.ReferenceValues.Count > 0)
                            {
                                foreach (var value in dataElement.ReferenceValues)
                                {
                                    JObject referenceValue = new JObject {
                                    {"oid", value.Oid},
                                    { "maxAge",value.MaxAge.Value},
                                    { "minAge",value.MinAge.Value},
                                    { "panicValue",value.PanicValue},
                                    { "description",value.Description}
                                };
                                    referenceValues.Add(referenceValue);
                                }
                                obj.Add("referenceValues", referenceValues);
                            }
                        }
                        obj.Add("tabIndex", tabIndex) ;
                        obj.Add("fieldName",name);
                        obj.Add("applicableSex", applicableSex);
                        fields.Add(obj);
                    }
                }
            }
            return fields;
        }


        /// <summary>
        /// 从表达式字符串中截取key
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public string GetKeyFromExpression(string expression)
        {
            string result = "";
            int startIndex = expression.IndexOf("(") + 1;
            int endIndex = expression.IndexOf(")");
            if (startIndex > 0 && endIndex > startIndex)
            {
                result = expression.Substring(startIndex, endIndex - startIndex);
                string temp = result.Split(',')[1].Trim();
                result = temp.Substring(1, temp.Length - 2);
            }

            return result;
        }

        /// <summary>
        ///  获取TextAlignment属性值(xml中)
        /// </summary>
        /// <param name="cell">单元格节点</param>
        /// <param name="root">根节点</param>
        /// <returns></returns>
        public string GetTextAlignString(XmlNode cell)
        {
            if (cell.Attributes["TextAlignment"] != null)
            {
                return cell.Attributes["TextAlignment"].Value;
            }
            else
            {
                return "MiddleCenter";
            }
        }
    }
}
